using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace WsdTestService.Metadata
{
    /// <summary>
    /// WSD Metadata服务（WS-MetadataExchange协议）
    /// 处理HTTP请求，返回设备描述XML文档
    /// </summary>
    public class WsdMetadataService : IDisposable
    {
        private readonly string _deviceUuid;
        private readonly string _printerName;
        private readonly string _localIp;
        private readonly int _httpPort;
        private readonly string _printerUri;

        public WsdMetadataService(string deviceUuid, string printerName, string localIp, int httpPort, string printerUri)
        {
            _deviceUuid = deviceUuid;
            _printerName = printerName;
            _localIp = localIp;
            _httpPort = httpPort;
            _printerUri = printerUri;
        }

        /// <summary>
        /// 处理HTTP请求
        /// </summary>
        public async Task HandleRequestAsync(HttpListenerRequest request, HttpListenerResponse response)
        {
            try
            {
                var path = request.Url.AbsolutePath.ToLowerInvariant();
                var method = request.HttpMethod.ToUpperInvariant();

                Console.WriteLine($"[HTTP] {method} {path} 来自 {request.RemoteEndPoint?.Address}");

                // 处理MetadataExchange请求（POST /metadatabroker 或 /wsd/metadata）
                if (method == "POST")
                {
                    var upperPath = path.ToUpperInvariant();
                    if (upperPath.IndexOf("METADATA", StringComparison.Ordinal) >= 0 || 
                        upperPath.IndexOf("METADATABROKER", StringComparison.Ordinal) >= 0 ||
                        path == "/metadatabroker" || path == "/wsd/metadata" || path == "/wsd/device/metadata")
                    {
                        await HandleMetadataExchangeAsync(request, response).ConfigureAwait(false);
                        return;
                    }
                }

                // 处理GET请求（设备描述文档）
                // Windows可能访问多种路径：/metadatabroker, /wsd/metadata, /wsd/device/metadata 等
                if (method == "GET")
                {
                    var upperPath = path.ToUpperInvariant();
                    if (path == "/" || 
                        path == "/metadatabroker" ||
                        path == "/wsd/metadata" ||
                        path == "/wsd/device/metadata" || 
                        upperPath.IndexOf("METADATA", StringComparison.Ordinal) >= 0)
                    {
                        await HandleGetMetadataAsync(request, response).ConfigureAwait(false);
                        return;
                    }
                }

                // 返回404
                Console.WriteLine($"[HTTP] 404 - 未找到路径: {path}");
                response.StatusCode = 404;
                response.ContentType = "text/plain";
                var notFoundBytes = Encoding.UTF8.GetBytes("Not Found");
                await response.OutputStream.WriteAsync(notFoundBytes, 0, notFoundBytes.Length).ConfigureAwait(false);
                response.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[HTTP] 处理请求时发生错误: {ex.Message}");
                try
                {
                    response.StatusCode = 500;
                    response.Close();
                }
                catch { }
            }
        }

        /// <summary>
        /// 处理GET Metadata请求（返回设备描述文档）
        /// </summary>
        private async Task HandleGetMetadataAsync(HttpListenerRequest request, HttpListenerResponse response)
        {
            var metadataXml = BuildDeviceMetadataXml();
            var bytes = Encoding.UTF8.GetBytes(metadataXml);

            response.StatusCode = 200;
            response.ContentType = "application/xml; charset=utf-8";
            response.ContentLength64 = bytes.Length;
            response.Headers.Add("Server", "WSD-Test-Service/1.0");

            await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
            response.Close();

            Console.WriteLine($"[HTTP] Metadata响应已发送（{bytes.Length} 字节）");
            Console.WriteLine($"[HTTP] Metadata XML内容（前500字符）：");
            Console.WriteLine(metadataXml.Substring(0, Math.Min(500, metadataXml.Length)));
            Console.WriteLine($"[HTTP] Metadata XML内容结束");
        }

        /// <summary>
        /// 处理POST MetadataExchange请求（SOAP）
        /// </summary>
        private async Task HandleMetadataExchangeAsync(HttpListenerRequest request, HttpListenerResponse response)
        {
            try
            {
                // 读取请求体
                string soapRequest = null;
                using (var reader = new StreamReader(request.InputStream, Encoding.UTF8))
                {
                    soapRequest = await reader.ReadToEndAsync().ConfigureAwait(false);
                    Console.WriteLine($"[HTTP] 收到MetadataExchange SOAP请求");
                    Console.WriteLine($"[HTTP] 请求内容前200字符：{soapRequest.Substring(0, Math.Min(200, soapRequest.Length))}");
                }

                // 从请求中提取MessageID（用于RelatesTo）
                var requestMessageId = ExtractMessageId(soapRequest);
                if (string.IsNullOrEmpty(requestMessageId))
                {
                    requestMessageId = "uuid:request-id"; // 默认值
                }

                // 构建SOAP响应
                var soapResponse = BuildMetadataExchangeResponse(requestMessageId);
                var bytes = Encoding.UTF8.GetBytes(soapResponse);

                response.StatusCode = 200;
                response.ContentType = "application/soap+xml; charset=utf-8";
                response.ContentLength64 = bytes.Length;
                response.Headers.Add("Server", "WSD-Test-Service/1.0");

                await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
                response.Close();

                Console.WriteLine($"[HTTP] MetadataExchange SOAP响应已发送（{bytes.Length} 字节）");
                Console.WriteLine($"[HTTP] 完整SOAP响应内容：");
                Console.WriteLine(soapResponse);
                Console.WriteLine($"[HTTP] SOAP响应内容结束");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[HTTP] 处理MetadataExchange时发生错误: {ex.Message}");
                response.StatusCode = 500;
                response.Close();
            }
        }

        /// <summary>
        /// 构建设备描述XML文档
        /// 根据物理打印机的格式，需要包含正确的Microsoft打印机端点定义
        /// </summary>
        /// <summary>
        /// 构建Metadata Sections（根据示例文档格式）
        /// 关键修复：ThisDevice和ThisModel中的字段应该使用wsdp:前缀，而不是prn:前缀
        /// </summary>
        private string BuildMetadataSections()
        {
            var metadataUrl = $"http://{_localIp}:{_httpPort}/wsd/device/metadata";
            // 将http://转换为ipp://格式
            var ippUri = _printerUri.Replace("http://", "ipp://").Replace("https://", "ipp://");

            // 关键修复：ThisDevice和ThisModel中的字段应该使用wsdp:前缀（设备配置文件命名空间）
            // 只有PrintDevice中的字段才使用prn:前缀（打印设备命名空间）
            return $@"            <wsx:MetadataSection Dialect=""http://schemas.xmlsoap.org/ws/2006/02/devprof/ThisDevice"">
                <wsdp:ThisDevice>
                    <wsdp:FriendlyName>{_printerName}</wsdp:FriendlyName>
                    <wsdp:FirmwareVersion>1.0</wsdp:FirmwareVersion>
                    <wsdp:SerialNumber>TEST-001</wsdp:SerialNumber>
                </wsdp:ThisDevice>
            </wsx:MetadataSection>
            
            <wsx:MetadataSection Dialect=""http://schemas.xmlsoap.org/ws/2006/02/devprof/ThisModel"">
                <wsdp:ThisModel>
                    <wsdp:Manufacturer>IPP Server</wsdp:Manufacturer>
                    <wsdp:ManufacturerUrl>http://ipp-server.local</wsdp:ManufacturerUrl>
                    <wsdp:ModelName>{_printerName}</wsdp:ModelName>
                    <wsdp:ModelNumber>1.0</wsdp:ModelNumber>
                    <wsdp:ModelUrl>{metadataUrl}</wsdp:ModelUrl>
                    <wsdp:PresentationUrl>http://{_localIp}:{_httpPort}/</wsdp:PresentationUrl>
                </wsdp:ThisModel>
            </wsx:MetadataSection>
            
            <wsx:MetadataSection Dialect=""http://schemas.microsoft.com/windows/2006/08/wdp/print"">
                <prn:PrintDevice>
                    <prn:DeviceId>{_deviceUuid}</prn:DeviceId>
                    <prn:PrinterUrl>{ippUri}</prn:PrinterUrl>
                    <prn:ConfigurationUrl>http://{_localIp}:{_httpPort}</prn:ConfigurationUrl>
                    <prn:SupportedCapabilities>
                        <prn:ContentTypes>application/pdf,image/jpeg,image/png,application/octet-stream</prn:ContentTypes>
                        <prn:ColorSupported>true</prn:ColorSupported>
                        <prn:DuplexSupported>true</prn:DuplexSupported>
                        <prn:CopiesSupported>true</prn:CopiesSupported>
                        <prn:CollateSupported>true</prn:CollateSupported>
                    </prn:SupportedCapabilities>
                    <prn:DeviceStatus>Online</prn:DeviceStatus>
                    <prn:ConsumableStatus>Ready</prn:ConsumableStatus>
                </prn:PrintDevice>
            </wsx:MetadataSection>";
        }

        private string BuildDeviceMetadataXml(bool includeXmlDeclaration = true)
        {
            var hostname = Dns.GetHostName();
            var metadataUrl = $"http://{_localIp}:{_httpPort}/wsd/device/metadata";

            var xmlDeclaration = includeXmlDeclaration ? @"<?xml version=""1.0"" encoding=""utf-8""?>" + Environment.NewLine : "";
            return $@"{xmlDeclaration}<wsdp:MetadataSection xmlns:wsdp=""http://schemas.xmlsoap.org/ws/2006/02/devprof""
                      xmlns:wsa=""http://schemas.xmlsoap.org/ws/2004/08/addressing""
                      xmlns:pws=""http://schemas.microsoft.com/windows/2006/08/wdp/print"">
    <wsdp:MetadataVersion>1</wsdp:MetadataVersion>
    <wsdp:ThisModel>
        <wsdp:Manufacturer>IPP Server</wsdp:Manufacturer>
        <wsdp:ManufacturerUrl>http://ipp-server.local</wsdp:ManufacturerUrl>
        <wsdp:ModelName>{_printerName}</wsdp:ModelName>
        <wsdp:ModelNumber>1.0</wsdp:ModelNumber>
        <wsdp:ModelUrl>{metadataUrl}</wsdp:ModelUrl>
        <wsdp:PresentationUrl>http://{_localIp}:{_httpPort}/</wsdp:PresentationUrl>
    </wsdp:ThisModel>
    <wsdp:ThisDevice>
        <wsdp:FriendlyName>{_printerName}</wsdp:FriendlyName>
        <wsdp:FirmwareVersion>1.0</wsdp:FirmwareVersion>
        <wsdp:SerialNumber>TEST-001</wsdp:SerialNumber>
    </wsdp:ThisDevice>
    <wsdp:DeviceCategory>
        <wsdp:Print />
    </wsdp:DeviceCategory>
    <pws:PrintDeviceType>
        <pws:PrinterName>{_printerName}</pws:PrinterName>
        <pws:EndpointReference>
            <wsa:Address>urn:uuid:{_deviceUuid}</wsa:Address>
            <wsa:Metadata>
                <wsa:MetadataVersion>1</wsa:MetadataVersion>
            </wsa:Metadata>
        </pws:EndpointReference>
        <pws:IPv4Address>{_localIp}</pws:IPv4Address>
        <pws:Location>网络打印机</pws:Location>
        <pws:EndpointURI>http://www.microsoft.com/printer</pws:EndpointURI>
        <pws:ResourceURI>{_printerUri}</pws:ResourceURI>
    </pws:PrintDeviceType>
    <pws:PrintService>
        <pws:EndpointReference>
            <wsa:Address>urn:uuid:{_deviceUuid}</wsa:Address>
        </pws:EndpointReference>
        <pws:EndpointURI>http://www.microsoft.com/printer</pws:EndpointURI>
        <pws:ResourceURI>{_printerUri}</pws:ResourceURI>
    </pws:PrintService>
</wsdp:MetadataSection>";
        }

        /// <summary>
        /// 从SOAP请求中提取MessageID
        /// </summary>
        private string ExtractMessageId(string soapMessage)
        {
            if (string.IsNullOrEmpty(soapMessage))
                return null;

            try
            {
                // 查找 <wsa:MessageID> 或 <a:MessageID> 或 <MessageID>
                var patterns = new[] { "<wsa:MessageID>", "<a:MessageID>", "<MessageID>" };
                
                foreach (var pattern in patterns)
                {
                    var startTag = soapMessage.IndexOf(pattern, StringComparison.OrdinalIgnoreCase);
                    if (startTag >= 0)
                    {
                        startTag = soapMessage.IndexOf(">", startTag) + 1;
                        var endTag = soapMessage.IndexOf("</", startTag);
                        if (endTag > startTag)
                        {
                            var messageId = soapMessage.Substring(startTag, endTag - startTag).Trim();
                            return messageId;
                        }
                    }
                }
            }
            catch { }
            
            return null;
        }

        /// <summary>
        /// 构建MetadataExchange SOAP响应
        /// </summary>
        private string BuildMetadataExchangeResponse(string relatesToMessageId)
        {
            // Windows期望MessageID使用urn:uuid格式
            var messageId = $"urn:uuid:{Guid.NewGuid():D}";
            
            // 确保RelatesTo使用正确的格式
            if (!string.IsNullOrEmpty(relatesToMessageId) && 
                !relatesToMessageId.StartsWith("urn:", StringComparison.OrdinalIgnoreCase) && 
                relatesToMessageId.StartsWith("uuid:", StringComparison.OrdinalIgnoreCase))
            {
                relatesToMessageId = "urn:" + relatesToMessageId;
            }
            else if (string.IsNullOrEmpty(relatesToMessageId))
            {
                relatesToMessageId = "urn:uuid:request-id";
            }

            // 根据示例文档，应该使用wsx:Metadata和wsx:MetadataSection结构
            // 每个MetadataSection需要Dialect属性
            var metadataSections = BuildMetadataSections();

            // 关键修复：Metadata响应使用2004版本的命名空间（与Windows兼容）
            return $@"<?xml version=""1.0"" encoding=""utf-8""?>
<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope""
            xmlns:wsa=""http://schemas.xmlsoap.org/ws/2004/08/addressing""
            xmlns:wsx=""http://schemas.xmlsoap.org/ws/2004/09/mex""
            xmlns:wsdp=""http://schemas.xmlsoap.org/ws/2006/02/devprof""
            xmlns:prn=""http://schemas.microsoft.com/windows/2006/08/wdp/print"">
    <s:Header>
        <wsa:Action>http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse</wsa:Action>
        <wsa:MessageID>{messageId}</wsa:MessageID>
        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
        <wsa:RelatesTo>{relatesToMessageId}</wsa:RelatesTo>
    </s:Header>
    <s:Body>
        <wsx:Metadata>
{metadataSections}
        </wsx:Metadata>
    </s:Body>
</s:Envelope>";
        }

        public void Dispose()
        {
            // 无需清理资源
        }
    }
}

